package com.zlfund.cat.demo;

import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.FloatEvaluator;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Build;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;

/**
 * Created by chenj
 * Created on 2017/7/14
 */

public class Switch extends View {
    private Context mContext;
    private int mHeight,mWidth;
    private Path mPath;
    private Paint mStrokePaint;         //边框画笔
    private Paint mSolidPaint;         //填充色画笔
    private Paint mCirclePaint;        //小圆球画笔
    private float mMarginLeft;                  //小圆球到左边距离
    private boolean mIsCheck;          //是否被选中
    private final static int CIRCLEPADDING = 3;
    private int mCircleWidth;
    private int mDefaultSolidColor,mTargetSolidColor;
    private int mDefaultStrokeColor,mTargetStrokeColor;
    private int mDefaultCircleColor,mTargetCircleColor;
    private int mSolidColor_;
    private int mCircleColor_;
    private int mStrokeColor_;
    private ObjectAnimator mTranslateAnim, mSolidColorAnim,mCircleColorAnim,mStrokeColorAnim;
    private int mStrokeWidth;
    private int mRealWidth;
    private int mRealHeight;
    private RectF mLeftRectF,mRightRectF;

    public interface OnCheckedChange{
        void onCheckChange(boolean isChecked);
    }

    public Switch(Context context) {
        this(context,null);
    }

    public Switch(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public Switch(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        TypedArray a = mContext.obtainStyledAttributes(attrs,R.styleable.Switch);
        mDefaultStrokeColor = a.getColor(R.styleable.Switch_default_stroke_color, Color.BLACK);
        mTargetStrokeColor = a.getColor(R.styleable.Switch_target_stroke_color, Color.BLACK);
        mDefaultCircleColor = a.getColor(R.styleable.Switch_default_circle_color, Color.RED);
        mDefaultSolidColor = a.getColor(R.styleable.Switch_default_solid_color, Color.WHITE);
        mTargetCircleColor = a.getColor(R.styleable.Switch_target_circle_color, Color.RED);
        mTargetSolidColor = a.getColor(R.styleable.Switch_target_solid_color, Color.WHITE);
        mIsCheck = a.getBoolean(R.styleable.Switch_checked,false);
        mSolidColor_ = mIsCheck ? mTargetSolidColor : mDefaultSolidColor;
        mCircleColor_ = mIsCheck ? mTargetCircleColor : mDefaultCircleColor;
        mStrokeColor_ = mIsCheck ? mTargetStrokeColor : mDefaultStrokeColor;
        mTranslateAnim = initAnim("marginLeft",new FloatEvaluator());
        mSolidColorAnim = initAnim("solidColor_",new ArgbEvaluator());
        mCircleColorAnim = initAnim("circleColor_",new ArgbEvaluator());
        mStrokeColorAnim = initAnim("strokeColor_",new ArgbEvaluator());

        mStrokeWidth = 4;
        mMarginLeft = 0;
        mPath = new Path();
        mCirclePaint = new Paint();
        mStrokePaint = new Paint();
        mSolidPaint = new Paint();
        initPaint(mCirclePaint,mSolidPaint,mStrokePaint);
        mStrokePaint.setStyle(Paint.Style.STROKE);
//        mTranslateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//            @Override
//            public void onAnimationUpdate(ValueAnimator animation) {
//                mMarginLeft = (float)(animation.getAnimatedValue());
//                postInvalidate();
//            }
//        });
//        mCircleColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//            @Override
//            public void onAnimationUpdate(ValueAnimator animation) {
//                mCircleColor_ = (int) animation.getAnimatedValue();
//                postInvalidate();
//            }
//        });
//        mSolidColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//            @Override
//            public void onAnimationUpdate(ValueAnimator animation) {
//                mSolidColor_ = (int) animation.getAnimatedValue();
//                postInvalidate();
//            }
//        });
//        mStrokeColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//            @Override
//            public void onAnimationUpdate(ValueAnimator animation) {
//                mStrokeColor_ = (int) animation.getAnimatedValue();
//                postInvalidate();
//            }
//        });
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
            mLeftRectF = new RectF();
            mRightRectF = new RectF();
        }
    }

    private ObjectAnimator initAnim(String propertyName, TypeEvaluator evaluator){
        ObjectAnimator anim = new ObjectAnimator();
        anim.setTarget(this);
        anim.setPropertyName(propertyName);
        return anim;
    }

    public void initPaint(Paint... paints){
        for (int i = 0; i < paints.length; i++) {
            paints[i].setAntiAlias(true);
            paints[i].setStrokeWidth(mStrokeWidth);
        }
    }

    public void startAnim(boolean isCheck){
        if (isCheck){
            mCircleColorAnim.setIntValues(mDefaultCircleColor,mTargetCircleColor);
            mTranslateAnim.setFloatValues(0,mWidth - mHeight);
            mSolidColorAnim.setIntValues(mDefaultSolidColor,mTargetSolidColor);
            mStrokeColorAnim.setIntValues(mDefaultStrokeColor,mTargetStrokeColor);
        }else {
            mCircleColorAnim.setIntValues(mTargetCircleColor,mDefaultCircleColor);
            mTranslateAnim.setFloatValues(mWidth - mHeight,0);
            mSolidColorAnim.setIntValues(mTargetSolidColor,mDefaultSolidColor);
            mStrokeColorAnim.setIntValues(mTargetStrokeColor, mDefaultStrokeColor);
        }
        mCircleColorAnim.setEvaluator(new ArgbEvaluator());
        mTranslateAnim.setEvaluator(new FloatEvaluator());
        mSolidColorAnim.setEvaluator(new ArgbEvaluator());
        mStrokeColorAnim.setEvaluator(new ArgbEvaluator());
        AnimatorSet set = new AnimatorSet();
        set.setDuration(200);
        set.setInterpolator(new AccelerateDecelerateInterpolator());
        set.playTogether(mTranslateAnim,mCircleColorAnim,mSolidColorAnim,mStrokeColorAnim);
        set.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mWidth == 0){
            mWidth = getWidth();
            mHeight = getHeight();
            mRealWidth = mWidth - mStrokeWidth * 2;
            mRealHeight = mHeight - mStrokeWidth * 2;
            mMarginLeft = mIsCheck ? mWidth - mHeight : 0;
            mCircleWidth = mHeight - CIRCLEPADDING * 2 - mStrokeWidth * 2;
        }
        if (mWidth <= 0 || mHeight <= 0)return;
        mPath.reset();
        mSolidPaint.setColor(mSolidColor_);
        mStrokePaint.setColor(mStrokeColor_);
        mCirclePaint.setColor(mCircleColor_);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
            mLeftRectF.set(mStrokeWidth, mStrokeWidth, mHeight - mStrokeWidth, mHeight - mStrokeWidth);
            mRightRectF.set(mWidth - mHeight + mStrokeWidth,mStrokeWidth,mWidth - mStrokeWidth,mHeight - mStrokeWidth);
            mPath.moveTo(mHeight / 2,mStrokeWidth);
            mPath.arcTo(mLeftRectF,270,-180,false);
            mPath.lineTo(mWidth - mHeight / 2,mHeight - mStrokeWidth);
            mPath.arcTo(mRightRectF,90,-180,false);
            mPath.lineTo(mHeight / 2,mStrokeWidth);
        }else {
            mPath.addRoundRect(mStrokeWidth,mStrokeWidth,mRealWidth + mStrokeWidth,mRealHeight + mStrokeWidth,mRealHeight / 2,mRealHeight / 2, Path.Direction.CW);
        }

//        mPath.addRoundRect(mStrokeWidth,mStrokeWidth,mRealWidth + mStrokeWidth,mRealHeight + mStrokeWidth,mRealHeight / 2,mRealHeight / 2, Path.Direction.CW);
        canvas.drawPath(mPath,mStrokePaint);
        canvas.drawPath(mPath,mSolidPaint);
        canvas.drawCircle(mHeight / 2.0f + mMarginLeft,mHeight / 2f,mCircleWidth / 2,mCirclePaint);
    }

    public void setCheck(boolean checked){
        this.setCheck(checked,true);
    }

    private void setCheck(boolean checked,boolean fromOut){
        boolean flag = mIsCheck == checked;
        mIsCheck = checked;
        if (mListener != null && !flag){
            mListener.onCheckChange(mIsCheck);
        }
        if (!fromOut){
            startAnim(mIsCheck);
        }else {
            mSolidColor_ = mIsCheck ? mTargetSolidColor : mDefaultSolidColor;
            mCircleColor_ = mIsCheck ? mTargetCircleColor : mDefaultCircleColor;
            mStrokeColor_ = mIsCheck ? mTargetStrokeColor : mDefaultStrokeColor;
            mMarginLeft = mIsCheck ? mWidth - mHeight : 0;
            postInvalidate();
        }
    }

    public float getMarginLeft() {
        return mMarginLeft;
    }

    private OnCheckedChange mListener;
    public void setOnCheckedChangeListener(OnCheckedChange listener){
        mListener = listener;
    }

    public void setMarginLeft(float marginLeft) {
        mMarginLeft = marginLeft;
        Log.i("mtag","===");
        postInvalidate();
    }

    public int getSolidColor_() {
        return mSolidColor_;
    }

    public void setSolidColor_(int solidColor_) {
        mSolidColor_ = solidColor_;
        postInvalidate();
    }

    public int getCircleColor_() {
        return mCircleColor_;
    }

    public void setCircleColor_(int circleColor_) {
        mCircleColor_ = circleColor_;
        postInvalidate();
    }

    public int getStrokeColor_() {
        return mStrokeColor_;
    }

    public void setStrokeColor_(int strokeColor_) {
        mStrokeColor_ = strokeColor_;
        postInvalidate();
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                if (mTranslateAnim.isRunning()){
                    return false;
                }
                return true;
            case MotionEvent.ACTION_CANCEL:
                return false;
            case MotionEvent.ACTION_UP:
                setCheck(!mIsCheck,false);
                return true;
        }
        return true;
    }
}
